#pragma once
#include <string>

#include "gtest/gtest.h"

#include "Utility/FileSystem/SGFileSystem.h"

#include "TestData/model/Link_TwoELe.hpp"
#include "TestData/model/OneBeam.hpp"
#include "TestData/model/QuadShell_OneEle.hpp"

#include "DBManager/IService/Input/Subcase/ISubcaseService.h"
#include "DBManager/IService/Result/IResultDomainsService.h"
#include "DBManager/IService/Result/Nodal/IDISPLACEMENTService.h"

#include "Export/VTKExport/VTKExport.h"

#include "SGFem/Pre/Assembly/Assembly.h"

using SG::FEMSolver::AssemblyEigen;

extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

// ELETYPE_Link 单元 Link_TwoELe 模型的单元测试
TEST (vtkOutputTest, LinkTest)
{
    // Input data
    Link_TwoEle model;
    DB_SERVICEFACTORY = model.GetModel ();

    auto& assembly = AssemblyEigen::GetInstance ();
    assembly.Clear ();
    auto                            para = DB_SERVICEFACTORY->get<ISubcaseService> ()->FindSubCase (1);
    SG::DataStructure::FEM::Subcase subcase (para);
    assembly.Initialize (DB_SERVICEFACTORY, subcase, { 1 });

    // Test data
    std::string filename    = "Link_TwoELe.vtk";
    std::string filenameT   = "Link_TwoELe_Target.vtk";
    std::string discription = "Link_TwoELe";

    std::vector<SG::DataStructure::Post::DISPLACEMENTData> displacementData (3);

    // 保存静力工况位移
    const auto& dispRepository = DB_SERVICEFACTORY->get<SG::DBManager::IDISPLACEMENTService> ();
    dispRepository->Add ({ SG::DataStructure::FEM::SOLType::SOL_SESTATIC, 1 }, displacementData);

    SG::Post::vtkOutput (DB_SERVICEFACTORY, filename, discription);
    auto fileTest = SG::Utility::FileSystem::getFullPath (filename);

    // Target data
    auto fileTarget = SG::Utility::FileSystem::getTestDataPath ("Post/ParaviewWriter/" + filenameT);

    // Check
    ASSERT_TRUE (SG::Utility::FileSystem::compareVTK (fileTarget, fileTest));
}

// ELETYPE_Beam 单元 OneBeam 模型的单元测试
TEST (vtkOutputTest, BeamTest)
{
    // Input data
    OneBeamCantilever model;
    DB_SERVICEFACTORY = model.GetModel ();

    auto& assembly = AssemblyEigen::GetInstance ();
    assembly.Clear ();
    auto                            para = DB_SERVICEFACTORY->get<ISubcaseService> ()->FindSubCase (1);
    SG::DataStructure::FEM::Subcase subcase (para);
    assembly.Initialize (DB_SERVICEFACTORY, subcase, { 1 });

    // Test data
    std::string filename    = "OneBeam";
    std::string discription = "OneBeam";

    std::vector<SG::DataStructure::Post::DISPLACEMENTData> displacementData (3);

    // 保存静力工况位移
    const auto& dispRepository = DB_SERVICEFACTORY->get<SG::DBManager::IDISPLACEMENTService> ();
    dispRepository->Add ({ SG::DataStructure::FEM::SOLType::SOL_SESTATIC, 1 }, displacementData);

    SG::Post::vtkOutput (DB_SERVICEFACTORY, filename + ".vtk", discription);
    auto fileTest = SG::Utility::FileSystem::getFullPath (filename + ".vtk");

    // Target data
    auto fileTarget = SG::Utility::FileSystem::getTestDataPath ("Post/ParaviewWriter/" + filename + "_Target.vtk");

    // Check
    ASSERT_TRUE (SG::Utility::FileSystem::compareVTK (fileTarget, fileTest));
}

// ELETYPE_ShellQuad4 单元 QuadShell_OneEle 模型的单元测试
TEST (vtkOutputTest, ShellQuad4Test)
{
    // Input data
    QuadShell_OneEle model;
    DB_SERVICEFACTORY = model.GetModel ();

    // 加入工况信息
    SG::DataStructure::FEM::Subcase subcase;
    subcase.AddParameter ({ "SUBCASE", "1" });
    subcase.AddParameter ({ "SOL", "101" });
    DB_SERVICEFACTORY->get<ISubcaseService> ()->Initial (subcase.Dump ());

    auto& assembly = AssemblyEigen::GetInstance ();
    assembly.Clear ();
    assembly.Initialize (DB_SERVICEFACTORY, subcase, { 1 });

    // Test data
    std::string filename    = "QuadShell_OneEle";
    std::string discription = "QuadShell_OneEle";

    std::vector<SG::DataStructure::Post::DISPLACEMENTData> displacementData (4);

    // 保存静力工况位移
    const auto& dispRepository = DB_SERVICEFACTORY->get<SG::DBManager::IDISPLACEMENTService> ();
    dispRepository->Add ({ SG::DataStructure::FEM::SOLType::SOL_SESTATIC, 1 }, displacementData);

    SG::Post::vtkOutput (DB_SERVICEFACTORY, filename + ".vtk", discription);
    auto fileTest = SG::Utility::FileSystem::getFullPath (filename + ".vtk");

    // Target data
    auto fileTarget = SG::Utility::FileSystem::getTestDataPath ("Post/ParaviewWriter/" + filename + "_Target.vtk");

    // Check
    ASSERT_TRUE (SG::Utility::FileSystem::compareVTK (fileTarget, fileTest));
}